#include <iostream>
#include <functional>
#include <stdint.h>
#include <memory>
#include <vector>
#include <unistd.h>
#include <unordered_map>

// 设计定时任务类
using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;
class TimerTask
{
private:
    uint64_t _id;            // 定时器任务id
    uint32_t _timeout;       // 定时任务的超时时间
    bool _canceled;          // false表示定时任务还未被取消 , true表示定时任务已经被取消
    TaskFunc _task_cb;       // 定时器对象要执行的定时任务
    ReleaseFunc _release_cb; // 用于删除TimerWheel中保存的定时器对象信息
public:
    TimerTask(uint64_t id, uint32_t delay, const TaskFunc &cb)
        : _id(id),
          _timeout(delay),
          _canceled(false),
          _task_cb(cb)
    {
    }
    ~TimerTask()
    {
        if (_canceled == false)
            _task_cb();
        _release_cb();
    }

    void SetRealseFunc(const ReleaseFunc &cb)
    {
        _release_cb = cb;
    }

    uint32_t DelayTime()
    {
        return _timeout;
    }

    void Cancel()
    {
        _canceled = true;
    }
};

// 时间轮设计
using WeakTask = std::weak_ptr<TimerTask>;  // 如果shared_ptr是针对原始对象构建的，那么计数器就不会增加，这样就会出现问题
using PtrTask = std::shared_ptr<TimerTask>; // 由智能指针来管理定时任务，计数器降到0则销毁对象，并执行定时任务
class TimerWheel
{
private:
    int _tick;                                // 秒针，走到哪里就释放哪里，就执行哪里的任务
    int _capacity;                            // 表盘最大数量，即为最大延迟时间
    std::vector<std::vector<PtrTask>> _wheel; // 时间轮
    std::unordered_map<uint64_t, WeakTask> _timers;

private:
    void RemoveTimer(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it != _timers.end())
        {
            _timers.erase(it);
        }
    }

public:
    TimerWheel()
        : _tick(0),
          _capacity(60),
          _wheel(_capacity)
    {
    }
    // 添加定时任务
    void TimerAdd(uint64_t id, uint32_t delay, const TaskFunc &cb)
    {
        // 创建定时任务，并用shared_ptr管理
        PtrTask pt(new TimerTask(id, delay, cb));
        pt->SetRealseFunc(std::bind(&TimerWheel::RemoveTimer, this, id));
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);  // 把定时任务对象加入到时间轮中
        _timers[id] = WeakTask(pt); // 把定时任务对象加入到哈希表中，管理定时任务对象(shared_ptr<TimerTask>)
    }
    // 刷新/延迟定时任务
    void TimerRefresh(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end()) // 没有找到定时任务，无法刷新/延迟
            return;
        PtrTask pt = it->second.lock(); // 获取weak_ptr管理的对象所对应的shared_ptr
        uint32_t delay = pt->DelayTime();
        int pos = (_tick + delay) % _capacity;
        _wheel[pos].push_back(pt);
    }

    // 执行定时任务，每隔一秒执行一次，相当于秒针向后走了一步，秒针走到哪里，就执行哪里的定时任务
    void RunTimerTask()
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear(); // 清除指定位置的数组，就会把数组中保存的所有定时器管理对象的shared_ptr释放掉
    }

    // 取消定时任务
    void TimerCancel(uint64_t id)
    {
        auto it = _timers.find(id);
        if (it == _timers.end())
            return;
        PtrTask pt = it->second.lock();
        pt->Cancel();
    }
};

class Test
{
public:
    Test()
    {
        std::cout << "构造" << std::endl;
    }

    ~Test()
    {
        std::cout << "析构" << std::endl;
    }
};

void DelTest(Test *t)
{
    delete t;
}

int main()
{
    TimerWheel tw;
    Test *t = new Test();
    tw.TimerAdd(210, 5, std::bind(DelTest, t));

    for (int i = 0; i < 5; i++)
    {
        sleep(1);
        tw.TimerRefresh(210);
        tw.RunTimerTask();
        std::cout << "刷新了一次定时任务,下一个5秒执行定时任务" << std::endl;
    }
    tw.TimerCancel(210);
    while (true)
    {
        sleep(1);
        std::cout << "--------------------------------------" << std::endl;
        tw.RunTimerTask();
    }
    return 0;
}